<template>
  <div class="w-full h-full p-2 bg-[#1a1a1a] text-white">
    <WindowTab
      :closeCallback="() => EndCall(isConnected ? CallStatus.end : CallStatus.cancel)"
      fontColor="text-white"
      obj="videoCall"
    >
      视频通话
    </WindowTab>
    <!-- 视频区域 -->
    <div ref="containerRef" :class="ContainerStyle" class="w-full h-[calc(100vh-155px)] my-2 gap-2"></div>
    <!-- 工具栏 -->
    <div>
      <!-- 通话时间 -->
      <div class="w-full text-center font-bold mt-2 mb-3">{{ callTipText }}</div>
      <!-- 按钮 -->
      <div class="flex flex-row justify-center items-center gap-5 cursor-pointer">
        <!-- 音频 -->
        <DevicePopover
          :activeDeviceId="activeAudioDeviceId"
          :deviceList="audioDeviceList"
          @changeDevice="(deviceId) => ChangeMediaDevice('audio', deviceId)"
        >
          <template #trigger>
            <CircularButton color="#fff" size="55px" @click="ToggleVoice">
              <span
                class="iconfont text-black leading-[60px]"
                :class="showVoice ? 'icon-maikefeng-XDY' : 'icon-maikefengguanbi'"
                style="font-size: 18px"
              ></span>
            </CircularButton>
          </template>
          <template #deviceLabel>
            <p class="text-xs text-fontPlaceholde">音频设备列表</p>
          </template>
        </DevicePopover>

        <!-- 关闭 -->
        <CircularButton color="#F56C6C" size="55px" @click="EndCall(isConnected ? CallStatus.end : CallStatus.cancel)">
          <span class="iconfont icon-guaduan text-white leading-[60px]" style="font-size: 22px"></span>
        </CircularButton>

        <!-- 视频 -->
        <DevicePopover
          :activeDeviceId="activeVideoDeviceId"
          :deviceList="videoDeviceList"
          @changeDevice="(deviceId) => ChangeMediaDevice('video', deviceId)"
        >
          <template #trigger>
            <CircularButton color="#fff" size="55px" @click="ToggleVideo">
              <span
                class="iconfont text-black leading-[60px]"
                :class="showVideo ? 'icon-24gf-videoCamera' : 'icon-a-Videocameracloseshexiangjiguanbi'"
                style="font-size: 16px"
              ></span>
            </CircularButton>
          </template>
          <template #deviceLabel>
            <p class="text-xs text-fontPlaceholde">视频设备列表</p>
          </template>
        </DevicePopover>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { IMessage, MessageType } from "@/types/chat";
import { CallContentStatus, CallStatus, ICallMessageType, IOpenCallParams, ISendRecordParams } from "@/types/call";
import { useRoute } from "vue-router";
import { useUser } from "@/store/modules/user";
import { useMitt } from "@/hooks/useMitt";
import { useWebRtc } from "@/hooks/useWebRtc";
import { MessageStrategyMap } from "@/tactics/message";
import { RecordTimer } from "@/utils/time";
import WindowTab from "@/components/WindowTab/index.vue";
import CircularButton from "@/components/CircularButton/index.vue";
import DevicePopover from "@/components/DevicePopover/index.vue";
import VideoCop from "./components/Video.vue";

const containerRef = ref<HTMLVideoElement | null>(null);
const {
  isConnected,
  audioDeviceList,
  videoDeviceList,
  activeAudioDeviceId,
  activeVideoDeviceId,
  mediaStreamMap,
  ChangeMediaDevice,
  LoadLocalStream,
  BuildVideoComponent,
  CreateOffer,
  CreateAnswer,
  AddAnswer,
  HandelCandidate,
  GetAllDevices,
  SendCandidate,
  ToggleLocalStream,
} = useWebRtc("video", containerRef, RecordCallTotalTimer);
const route = useRoute();
const user = useUser();
let showVideo = ref(true);
let showVoice = ref(true);
let callRecordTime = ref(0);
let callTipText = ref("等待对方加入中...");
let timer: NodeJS.Timeout | null = null;
// 对方信息
const RouteParams = computed<IOpenCallParams>(() => {
  if (!route.query.requestParams || typeof route.query.requestParams !== "string") return;
  return JSON.parse(route.query.requestParams);
});

// 视频容器样式
const ContainerStyle = computed(() => {
  const size = mediaStreamMap.value.size;
  if (size <= 1) return "";
  if (size >= 6) return "grid grid-cols-6 justify-center items-center";
  return `grid grid-cols-${size} justify-evenly items-center`;
});

// 处理消息呼叫状态
function HandelMessage(message: IMessage) {
  if (message.messageType != MessageType.videoCall) return;
  switch (message.callStatus) {
    // 同意通话
    case CallStatus.agree:
      HandelMessageAgree(message);
      break;
    // 拒绝
    case CallStatus.reject:
      SendRecordTime({ status: CallStatus.reject, data: "通话被拒绝" });
      window.electronApi.controlTabBar({
        obj: "videoCall",
        type: "close",
      });
      break;
    // 取消
    case CallStatus.cancel:
      SendRecordTime({ status: CallStatus.reject, data: "通话取消" });
      window.electronApi.controlTabBar({
        obj: "videoCall",
        type: "close",
      });
      break;
    // 结束
    case CallStatus.end:
      SendRecordTime({ status: CallStatus.end, data: "通话时长" + callTipText.value });
      window.electronApi.controlTabBar({
        obj: "videoCall",
        type: "close",
      });
      break;
  }
}

// 处理同意通话
function HandelMessageAgree(message: IMessage) {
  let data = JSON.parse(message.content) as ICallMessageType;
  const { id, name, avatar } = RouteParams.value.callCandidateLists[0];
  switch (data.type) {
    // 对方同意通话->发送offer
    case CallContentStatus.Join:
      // 发送offer 说明我们是主动方 可能存在多个候选者
      setTimeout(() => {
        RouteParams.value.callCandidateLists.forEach(async (candidate) => {
          await CreateOffer(candidate, CreateOfferCallBack);
        });
      }, 1000);
      break;
    // 接受到 offer -> 发送answer
    case CallContentStatus.Offer:
      console.log("接受到了offer,准备创建anser");
      // 发送offer 说明我们是被动方 只有一个候选者
      CreateAnswer({ id, name, avatar }, data.content as RTCSessionDescriptionInit, CreateAnswerCallback);
      break;
    // 接受到了answer ->添加到本地 开始建立连接
    case CallContentStatus.Answer:
      console.log("接受到了answer准备添加answer,发送给对方自己的candidate");
      AddAnswer(message.sendId, data.content as RTCSessionDescriptionInit, SendCandidateCallback);
      break;
    // 对方给你发送了candidate
    case CallContentStatus.SendCandidate:
      console.log("接受到了对方的candidate,发送给对方自己的candidate");
      console.log("对方传输的内容为->s", data.content);
      SendCandidate(message.sendId, data.content as RTCIceCandidateInit[], SendCandidateCallback);
      break;
    // 接受到了对方candidate
    case CallContentStatus.ReceiverCandidate:
      console.log("对方传输的内容为->r", data.content);
      HandelCandidate(data.content as RTCIceCandidateInit[]);
      break;
  }
}

// 发送offer
function CreateOfferCallBack(candidateId: number, offer: RTCSessionDescriptionInit) {
  console.log("发送offer个体", candidateId);
  SendMessage({
    toId: candidateId,
    content: JSON.stringify({
      type: CallContentStatus.Offer,
      content: offer,
    }),
  });
  console.log("发送offer成功");
}

//发送answer
function CreateAnswerCallback(candidateId: number, answer: RTCSessionDescriptionInit) {
  console.log("准备发送anser");
  SendMessage({
    toId: candidateId,
    content: JSON.stringify({
      type: CallContentStatus.Answer,
      content: answer,
    }),
  });
  console.log("发送answser成功");
}

//发送candidate
function SendCandidateCallback(candidateId: number, candidateList: RTCIceCandidate[], type: CallContentStatus) {
  SendMessage({
    toId: candidateId,
    content: JSON.stringify({
      type,
      content: candidateList,
    }),
  });
}

// 记录通话时长
function RecordCallTotalTimer() {
  if (timer) {
    clearInterval(timer);
    callRecordTime.value = 0;
  }
  timer = setInterval(() => {
    callTipText.value = RecordTimer(callRecordTime.value++);
  }, 1000);
}

// 开启或关闭麦克风
function ToggleVoice() {
  showVoice.value = !showVoice.value;
  ToggleLocalStream("audio");
}

// 开启或关闭视频
function ToggleVideo() {
  showVideo.value = !showVideo.value;
  ToggleLocalStream("video");
}

// 结束通话
function EndCall(callStatus: CallStatus) {
  RouteParams.value.callCandidateLists.forEach((c) => SendMessage({ toId: c.id, callStatus }));
  SendRecordTime({
    status: callStatus,
    data: callStatus === CallStatus.end ? "通话时长" + callTipText.value : "通话取消",
  });
  window.electronApi.controlTabBar({ obj: "videoCall", type: "close" });
}

// 发送消息通知对方
function SendMessage(data: Partial<IMessage>) {
  const { chatType, messageType, sessionId } = RouteParams.value;
  const strategy = MessageStrategyMap[MessageType.videoCall];
  let dafeultMesage = {
    sendId: user.userId!,
    sessionId,
    chatType,
    messageType,
    callStatus: CallStatus.agree,
  };
  let message = strategy.mergeData(Object.assign(dafeultMesage, data));
  strategy.sendMessage(message);
}

// 发送通话汇总
function SendRecordTime(data: ISendRecordParams) {
  const { chatType, sessionId, initiatorId } = RouteParams.value;
  if (user.userId != initiatorId) return;
  const strategy = MessageStrategyMap[MessageType.videoCall];
  const defaultMessage = strategy.mergeData({
    sendId: user.userId!,
    sessionId,
    chatType,
    callStatus: CallStatus.record,
    content: JSON.stringify(data),
  });
  RouteParams.value.callCandidateLists.forEach((c) => {
    strategy.sendMessage({ ...defaultMessage, toId: c.id });
  });
}

onMounted(async () => {
  await GetAllDevices();
  const { name, avatar, id } = user.userInfo!;
  let mediaStream = await LoadLocalStream();
  mediaStreamMap.value.set(id, { mediaStream, peerConnection: null });
  BuildVideoComponent({ id, name, avatar }, VideoCop);
});

useMitt.on("webrtc", HandelMessage);
</script>

<style lang="scss" scoped></style>
